/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <jni.h>
#include <time.h>
#include <android/log.h>
#include <android/bitmap.h>

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "mosaic.h"

#define  LOG_TAG    "Contour"
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#define MIN(x,y) x > y ? y : x 
#define MAX(x,y) x > y ? x : y
/* Set to 1 to enable debug log traces. */
#define DEBUG 0

/* Set to 1 to optimize memory stores when generating plasma. */

/* Return current time in milliseconds */
static double now_ms(void)
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec*1000. + tv.tv_usec/1000.;
}
void contourlib(int* dstBuff, int dstwidth, int dstheight, unsigned char* maskBuff, int maskWidth, int maskHeight , float scale, int padX, int padY, int moveX, int moveY, int drawLeft, int drawTop, int drawRight, int drawBottom, int color1, int color2);
JNIEXPORT void JNICALL Java_com_sec_android_mimage_photoeditor_jni_ContourJNI_nativeContour(JNIEnv * env, jobject  obj, jobject input_bitmap,
																			  jbyteArray mask, int maskWidth, int maskHeight,
																			  int padX, int padY, int color, float scale, int moveX, int moveY, int drawLeft, int drawTop, int drawRight, int drawBottom)
{
    AndroidBitmapInfo	input_info/*, output_info*/;
    void				*input_pixels/*, *output_pixels*/;
	unsigned char		*buffer;
    int					ret;

    if ((ret = AndroidBitmap_getInfo(env, input_bitmap, &input_info)) < 0) {
        LOGE("input_bitmap AndroidBitmap_getInfo() failed ! error=%d", ret);
        return;
    }

    if (input_info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
        LOGE("Bitmap format is not RGB_888 !");
        return;
    }
	
    if ((ret = AndroidBitmap_lockPixels(env, input_bitmap, &input_pixels)) < 0) {
        LOGE("input_pixels AndroidBitmap_lockPixels() failed ! error=%d", ret);
    }

	/*if ((ret = AndroidBitmap_getInfo(env, output_bitmap, &output_info)) < 0) {
        LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
        return;
    }

    if (output_info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
        LOGE("Bitmap format is not RGB_888 !");
        return;
    }
	
    if ((ret = AndroidBitmap_lockPixels(env, output_bitmap, &output_pixels)) < 0) {
        LOGE("output_pixels AndroidBitmap_lockPixels() failed ! error=%d", ret);
    }*/

	buffer = (unsigned char*)(*env)->GetByteArrayElements( env, mask , 0 );

	//mosaic((unsigned char*)input_pixels, (unsigned char*)output_pixels, input_info.width, input_info.height, 0 );
	contourlib((int*)input_pixels, input_info.width, input_info.height, buffer, maskWidth, maskHeight, scale, padX, padY, moveX, moveY,
		drawLeft, drawTop, drawRight, drawBottom, color, color ^ 0x00ffffff );
	(*env)->ReleaseByteArrayElements(env, mask, buffer, 0);

    AndroidBitmap_unlockPixels(env, input_bitmap);
	//AndroidBitmap_unlockPixels(env, output_bitmap);
}

void contourlib(int* dstBuff, int dstwidth, int dstheight, unsigned char* maskBuff, int maskWidth, int maskHeight , float scale, int padX, int padY, int moveX, int moveY, int drawLeft, int drawTop, int drawRight, int drawBottom, int color1, int color2)
{
	int i, j;
	int ypos, xpos;
	int iScale;
	int imoveY, imoveX;
	int ypos0, ypos1;
	int xpos0, xpos1;
	int color = color1;
	int round;
	int maskSize;
	short isMaskArea;
	round = 32768;
	iScale = (int)(scale * 65536);	
	imoveX = (moveX * iScale ) + round;
	imoveY = (moveY * iScale ) + round;

	maskSize = maskWidth * maskHeight;
	isMaskArea = 0;
	/*for( i = drawTop; i <= drawBottom; ++i )
	{
		int y_idx = (i+padY) * dstwidth;
		for( j = drawLeft; j <= drawRight; ++j )
		{
			dstBuff[y_idx + (j+padX)] = 0;
		}		
	}*/

	for( i = 0; i < dstheight ; ++i)
	{
		int y_idx = (i+padY) * dstwidth;

		short color_flag = 0;
		if( i >= drawTop && i <= drawBottom )
		{
			isMaskArea = 1;
			ypos =  i * iScale + imoveY ;
			ypos0 = (ypos - iScale) >> 16;
			ypos1 = (ypos + iScale) >> 16;
			ypos = MIN( ypos >> 16, maskHeight - 1); 
			ypos = MAX( ypos, 0);

			ypos = ypos * maskWidth;
			ypos0 = ypos0 * maskWidth;
			ypos1 = ypos1 * maskWidth;

			if( ((int)(i * .2f) % 2 == 0))
				color_flag = 1;
		}
		else
			isMaskArea = 0;

		for( j = 0 ; j < dstwidth ; ++j )
		{
			if( j >= drawLeft && j <= drawRight && isMaskArea)
			{
				xpos =  j * iScale + imoveX;
				xpos0 = (xpos - iScale) >> 16;
				xpos1 = (xpos + iScale) >> 16; 
				xpos = MIN( xpos >> 16, maskWidth -1);
				xpos = MAX( xpos, 0);
				if((ypos1 + xpos) > maskSize)
					continue;
				if(  maskBuff[ ypos + xpos ] == 1 )
				{
					if( color_flag )
					{
						if( ((int)(j * .2f) % 2 == 0))
							color = color1;
						else
							color = color2;
					}
					else
					{
						if( ((int)(j * .2f) % 2 == 0))
							color = color2;
						else 
							color = color1;
					}

					if(i == drawTop || i == drawBottom || j == drawLeft || j == drawRight)
						dstBuff[ y_idx + (j+padX) ] = color;
					else if( maskBuff[ ypos + xpos1 ] == 0 || 
							maskBuff[ ypos1 + xpos ] == 0 ||
							maskBuff[ ypos + xpos0 ] == 0 ||
							maskBuff[ ypos0 + xpos ] == 0 )
					{						
						dstBuff[ y_idx + (j+padX) ] = color;
					}
					else
						dstBuff[ y_idx + (j+padX) ] = 0;
				}
				else
					dstBuff[ y_idx + (j+padX) ] = 0;
			}
			else
			{
				if(dstBuff[ y_idx + (j+padX) ] != 0)
					dstBuff[ y_idx + (j+padX) ] = 0;
			}
		}
	}
}
